/* Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.pointlion.mvc.admin.oa.workflow.rest;

import com.fasterxml.jackson.databind.node.ArrayNode;
import com.fasterxml.jackson.databind.node.ObjectNode;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import org.flowable.engine.*;
//import org.flowable.engine.impl.pvm.PvmTransition;
//import org.flowable.engine.impl.pvm.process.ActivityImpl;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.jfinal.core.Controller;
import com.pointlion.plugin.flowable.FlowablePlugin;
import org.flowable.engine.history.HistoricProcessInstance;
import org.flowable.engine.impl.persistence.entity.ProcessDefinitionEntity;

import java.util.List;

public class ProcessInstanceHighlightsResource extends Controller{
	private ProcessEngine pEngine = FlowablePlugin.buildProcessEngine();

	private RuntimeService runtimeService = pEngine.getRuntimeService();

	private RepositoryService repositoryService = pEngine.getRepositoryService();

	private HistoryService historyService = pEngine.getHistoryService();

	protected ObjectMapper objectMapper = new ObjectMapper();

	public void getHighlighted() {
		String processInstanceId = getPara("processInstanceId");
		String callback = getPara("callback").toString();
		ObjectNode responseJSON = objectMapper.createObjectNode();
		responseJSON.put("processInstanceId", processInstanceId);
		ArrayNode activitiesArray = objectMapper.createArrayNode();
		ArrayNode flowsArray = objectMapper.createArrayNode();
		try {
//			ProcessInstance processInstance = runtimeService.createProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
			HistoricProcessInstance processInstance = historyService.createHistoricProcessInstanceQuery().processInstanceId(processInstanceId).singleResult();
			ProcessDefinitionEntity processDefinition = (ProcessDefinitionEntity) repositoryService.getProcessDefinition(processInstance.getProcessDefinitionId());
			responseJSON.put("processDefinitionId", processInstance.getProcessDefinitionId());
			List<Record> list = Db.find("select * from act_ru_task t where t.PROC_INST_ID_='"+processInstanceId+"'");
			if(list!=null&&list.size()>0){
				List<String> highLightedActivities = runtimeService.getActiveActivityIds(processInstanceId);
				for (String activityId : highLightedActivities) {
					activitiesArray.add(activityId);
				}
			}
//			List<String> highLightedFlows = getHighLightedFlows(processDefinition, processInstanceId);
//			for (String flow : highLightedFlows) {
//				flowsArray.add(flow);
//			}
		} catch (Exception e) {
		  e.printStackTrace();
		}
		responseJSON.put("activities", activitiesArray);
		responseJSON.put("flows", flowsArray);
		renderJson(callback+"("+responseJSON.toString()+")");
	}

//
//	/**
//	 * getHighLightedFlows
//	 *
//	 * @param processDefinition
//	 * @param processInstanceId
//	 * @return
//	 */
//	private List<String> getHighLightedFlows(ProcessDefinitionEntity processDefinition, String processInstanceId) {
//
//    List<String> highLightedFlows = new ArrayList<String>();
//
//    List<HistoricActivityInstance> historicActivityInstances = historyService.createHistoricActivityInstanceQuery()
//        .processInstanceId(processInstanceId)
//        //order by startime asc is not correct. use default order is correct.
//        //.orderByHistoricActivityInstanceStartTime().asc()/*.orderByActivityId().asc()*/
//        .list();
//
//    LinkedList<HistoricActivityInstance> hisActInstList = new LinkedList<HistoricActivityInstance>();
//    hisActInstList.addAll(historicActivityInstances);
//
//    getHighlightedFlows(processDefinition.getActivities(), hisActInstList, highLightedFlows);
//
//    return highLightedFlows;
//	}
//
//	/**
//	 * getHighlightedFlows
//	 *
//	 * code logic:
//	 * 1. Loop all activities by id asc order;
//	 * 2. Check each activity's outgoing transitions and eventBoundery outgoing transitions, if outgoing transitions's destination.id is in other executed activityIds, add this transition to highLightedFlows List;
//	 * 3. But if activity is not a parallelGateway or inclusiveGateway, only choose the earliest flow.
//	 *
//	 * @param activityList
//	 * @param hisActInstList
//	 * @param highLightedFlows
//	 */
//	private void getHighlightedFlows(List<ActivityImpl> activityList, LinkedList<HistoricActivityInstance> hisActInstList, List<String> highLightedFlows){
//
//    //check out startEvents in activityList
//    List<ActivityImpl> startEventActList = new ArrayList<ActivityImpl>();
//    Map<String, ActivityImpl> activityMap = new HashMap<String, ActivityImpl>(activityList.size());
//    for(ActivityImpl activity : activityList){
//
//      activityMap.put(activity.getId(), activity);
//
//      String actType = (String) activity.getProperty("type");
//      if (actType != null && actType.toLowerCase().indexOf("startevent") >= 0){
//        startEventActList.add(activity);
//      }
//    }
//
//    //These codes is used to avoid a bug:
//    //ACT-1728 If the process instance was started by a callActivity, it will be not have the startEvent activity in ACT_HI_ACTINST table
//    //Code logic:
//    //Check the first activity if it is a startEvent, if not check out the startEvent's highlight outgoing flow.
//    HistoricActivityInstance firstHistActInst = hisActInstList.getFirst();
//    String firstActType = (String) firstHistActInst.getActivityType();
//    if (firstActType != null && firstActType.toLowerCase().indexOf("startevent") < 0){
//      PvmTransition startTrans = getStartTransaction(startEventActList, firstHistActInst);
//      if (startTrans != null){
//        highLightedFlows.add(startTrans.getId());
//      }
//    }
//
//    while (!hisActInstList.isEmpty()) {
//      HistoricActivityInstance histActInst = hisActInstList.removeFirst();
//      ActivityImpl activity = activityMap.get(histActInst.getActivityId());
//      if (activity != null) {
//        boolean isParallel = false;
//        String type = histActInst.getActivityType();
//        if ("parallelGateway".equals(type) || "inclusiveGateway".equals(type)){
//          isParallel = true;
//        } else if ("subProcess".equals(histActInst.getActivityType())){
//          getHighlightedFlows(activity.getActivities(), hisActInstList, highLightedFlows);
//        }
//
//        List<PvmTransition> allOutgoingTrans = new ArrayList<PvmTransition>();
//        allOutgoingTrans.addAll(activity.getOutgoingTransitions());
//        allOutgoingTrans.addAll(getBoundaryEventOutgoingTransitions(activity));
//        List<String> activityHighLightedFlowIds = getHighlightedFlows(allOutgoingTrans, hisActInstList, isParallel);
//        highLightedFlows.addAll(activityHighLightedFlowIds);
//      }
//    }
//	}
//
//	/**
//	 * Check out the outgoing transition connected to firstActInst from startEventActList
//	 *
//	 * @param startEventActList
//	 * @param firstActInst
//	 * @return
//	 */
//	private PvmTransition getStartTransaction(List<ActivityImpl> startEventActList, HistoricActivityInstance firstActInst){
//    for (ActivityImpl startEventAct: startEventActList) {
//      for (PvmTransition trans : startEventAct.getOutgoingTransitions()) {
//        if (trans.getDestination().getId().equals(firstActInst.getActivityId())) {
//          return trans;
//        }
//      }
//    }
//    return null;
//	}
//
//	/**
//	 * getBoundaryEventOutgoingTransitions
//	 *
//	 * @param activity
//	 * @return
//	 */
//	private List<PvmTransition> getBoundaryEventOutgoingTransitions(ActivityImpl activity){
//    List<PvmTransition> boundaryTrans = new ArrayList<PvmTransition>();
//    for(ActivityImpl subActivity : activity.getActivities()){
//      String type = (String)subActivity.getProperty("type");
//      if(type!=null && type.toLowerCase().indexOf("boundary")>=0){
//        boundaryTrans.addAll(subActivity.getOutgoingTransitions());
//      }
//    }
//    return boundaryTrans;
//	}
//
//	/**
//	 * find out single activity's highlighted flowIds
//	 *
//	 * @param activity
//	 * @param hisActInstList
//	 * @param isExclusive if true only return one flowId(Such as exclusiveGateway, BoundaryEvent On Task)
//	 * @return
//	 */
//	private List<String> getHighlightedFlows(List<PvmTransition> pvmTransitionList, LinkedList<HistoricActivityInstance> hisActInstList, boolean isParallel){
//
//    List<String> highLightedFlowIds = new ArrayList<String>();
//
//    PvmTransition earliestTrans = null;
//    HistoricActivityInstance earliestHisActInst = null;
//
//    for (PvmTransition pvmTransition : pvmTransitionList) {
//
//      String destActId = pvmTransition.getDestination().getId();
//      HistoricActivityInstance destHisActInst = findHisActInst(hisActInstList, destActId);
//      if (destHisActInst != null) {
//        if (isParallel) {
//          highLightedFlowIds.add(pvmTransition.getId());
//        } else if (earliestHisActInst == null || (earliestHisActInst.getId().compareTo(destHisActInst.getId()) > 0)) {
//          earliestTrans = pvmTransition;
//          earliestHisActInst = destHisActInst;
//        }
//      }
//    }
//
//    if ((!isParallel) && earliestTrans!=null){
//      highLightedFlowIds.add(earliestTrans.getId());
//    }
//
//    return highLightedFlowIds;
//	}
//
//	private HistoricActivityInstance findHisActInst(LinkedList<HistoricActivityInstance> hisActInstList, String actId){
//    for (HistoricActivityInstance hisActInst : hisActInstList){
//      if (hisActInst.getActivityId().equals(actId)){
//        return hisActInst;
//      }
//    }
//    return null;
//	}





}
